package QC.MessageBox.service;

import QC.MessageBox.beans.rcform.RCSingleForm;
import QC.MessageBox.common.Constants;
import QC.MessageBox.common.HttpUtils;
import QC.MessageBox.common.RCUtils;
import com.ning.http.client.AsyncHttpClient;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.RequestOptions;
import io.vertx.core.json.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * Created by Andaren on 2017/4/11.
 * Used for: http服务类
 */
public class HttpService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpService.class);

    // 融云接口API调用：是否测试环境
    public static Boolean RC_ISTEST = true;

    // APP后台接口API调用：是否测试环境
    public static Boolean APPBACK_ISTEST = true;
    private HttpClient client;

    public HttpService(HttpClient httpClient) {
        this.client = httpClient;
    }

    /****************************************************************************************************
     *      微信http服务
     * **************************************************************************************************
     */

    /**
     * 上传媒体文件获取media_id
     *      URL:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
     *      [这里AsyncHttpClient对象可以重用吗]
     * @param accessToken
     * @param type
     * @param file
     * @return
     */
    public Future<String> getMediaIdByPostMediaToWX(String accessToken, String type, File file) {
        Future<String> postMediaFut = Future.future();
        AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
        StringBuilder postUrlSb = new StringBuilder();
        postUrlSb.append(Constants.WX_INTERFACE_HOST_PROXY)
                .append("/cgi-bin/media/upload?access_token=").append(accessToken)
                .append("&type=").append(type);
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("name", "media");

        try{
            HttpUtils.postWithFileListAndParamMap(asyncHttpClient, postUrlSb.toString(), file, paramMap).setHandler(as -> {
                if (as.failed()) {
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    postMediaFut.fail(as.cause());
                } else {
                    JsonObject returnJson = as.result();
                    LOGGER.info("[post媒体数据到微信token={}]received->\n {}", accessToken,returnJson);
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    switch (type) {
                        case "image" :
                            if (StringUtils.isBlank(returnJson.getString("media_id"))) {
                                postMediaFut.fail(returnJson.encodePrettily());
                            } else {
                                postMediaFut.complete(returnJson.getString("media_id"));
                            }
                            break;
                        case "thumb" :
                            if (StringUtils.isBlank(returnJson.getString("thumb_media_id"))) {
                                postMediaFut.fail(returnJson.encodePrettily());
                            } else {
                                postMediaFut.complete(returnJson.getString("thumb_media_id"));
                            }
                            break;
                        case "video" :
                            if (StringUtils.isBlank(returnJson.getString("media_id"))) {
                                postMediaFut.fail(returnJson.encodePrettily());
                            } else {
                                postMediaFut.complete(returnJson.getString("media_id"));
                            }
                            break;
                    }

                }
            });
        } catch (Exception e) {
            postMediaFut.fail(e);
        }
        return postMediaFut;
    }

    /**
     * 群发图文消息时上传图片
     *      https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
     *      [这里AsyncHttpClient对象可以重用吗]
     * @param accessToken
     * @param file
     * @return
     */
    public Future<String> uploadImageWhenGroupSend(String accessToken, File file) {
        Future<String> postMediaFut = Future.future();
        AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
        StringBuilder postUrlSb = new StringBuilder();
        postUrlSb.append(Constants.WX_INTERFACE_HOST_PROXY)
                .append("/cgi-bin/media/uploadimg?access_token=").append(accessToken);
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("name", "media");
        try{
            HttpUtils.postWithFileListAndParamMap(asyncHttpClient, postUrlSb.toString(), file, paramMap).setHandler(as -> {
                if (as.failed()) {
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    postMediaFut.fail(as.cause());
                } else {
                    JsonObject returnJson = as.result();
                    LOGGER.info("[群发图文消息时上传图片token={}]received->\n {}", accessToken,returnJson);
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    if (StringUtils.isBlank(returnJson.getString("url"))) {
                        postMediaFut.fail(returnJson.encodePrettily());
                    } else {
                        postMediaFut.complete(returnJson.getString("url"));
                    }
                }
            });
        } catch (Exception e) {
            postMediaFut.fail(e);
        }
        return postMediaFut;
    }

    /**
     * 上传永久素材
     *      https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE
     *     "https://api.weixin.qq.com/cgi-bin/material/add_material?type=";
     * @param accessToken
     * @param file
     * @return
     */
    public Future<String> uploadPermanentMedia(String accessToken, File file, String type) {
        Future<String> postMediaFut = Future.future();
        AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
        StringBuilder postUrlSb = new StringBuilder();
        postUrlSb.append(Constants.WX_INTERFACE_HOST_PROXY)
                .append("/cgi-bin/material/add_material?access_token=").append(accessToken)
                .append("&type=").append(type);
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("name", "media");
        try{
            HttpUtils.postWithFileListAndParamMap(asyncHttpClient, postUrlSb.toString(), file, paramMap).setHandler(as -> {
                if (as.failed()) {
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    postMediaFut.fail(as.cause());
                } else {
                    JsonObject returnJson = as.result();
                    LOGGER.info("[上传永久素材token={}]received->\n {}", accessToken,returnJson);
                    // 删除本地文件
                    file.delete();
                    // 关闭连接
                    if (!asyncHttpClient.isClosed()) {
                        asyncHttpClient.closeAsynchronously();
                    }
                    if (StringUtils.isBlank(returnJson.getString("media_id"))) {
                        postMediaFut.fail(returnJson.encodePrettily());
                    } else {
                        postMediaFut.complete(returnJson.getString("media_id"));
                    }
                }
            });
        } catch (Exception e) {
            postMediaFut.fail(e);
        }
        return postMediaFut;
    }

    /****************************************************************************************************
     *      融云http服务
     * **************************************************************************************************
     */

    /**
     * 调用融云发送单聊消息接口
     *      http://api.cn.ronghub.com/message/private/publish.json
     * @param rcSingleForm
     * @return
     */
    public Future<Void> postSingleMsg(RCSingleForm rcSingleForm) {
        Future<Void> fut = Future.future();
        // 构造请求
        HttpClientRequest request = client.post(new RequestOptions()
                        .setHost(Constants.RC_INTERFACE_HOST)
                        .setPort(Constants.RC_INTERFACE_PORT)
                        .setURI(Constants.RC_INTERFACE_URI_SINGLEMSG)
                , response -> {
                    response.bodyHandler(buffer -> {
                        LOGGER.info("[调用融云发送单聊消息接口]received : " + buffer);
                        JsonObject result = buffer.toJsonObject();
                        if (200 == result.getInteger("code")) {
                            fut.complete();
                        } else {
                            fut.fail(String.valueOf(result.getInteger("code")));
                        }
                    }).exceptionHandler(exception -> {
                        LOGGER.error("融云消息发送异常：" + exception.getMessage());
                    });
                });
        // 设置请求头并发送
        setRCRequestHeaders(request).end(rcSingleForm.formatBody());
        return fut;
    }

    /**
     * 设置融云请求头信息
     * @param request
     * @return
     */
    public HttpClientRequest setRCRequestHeaders(HttpClientRequest request) {
        // 拼接请求头
        String nonce = String.valueOf(Math.random() * 1000000);
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String signature = RCUtils.getRongCloudSign(HttpService.RC_ISTEST ? Constants.RC_APP_SECRET_TEST : Constants.RC_APP_SECRET,
                nonce, timestamp);
        request
                .putHeader("App-Key", HttpService.RC_ISTEST ? Constants.RC_APP_APPKEY_TEST : Constants.RC_APP_APPKEY)
                .putHeader("Nonce", nonce)
                .putHeader("Timestamp", timestamp)
                .putHeader("Signature", signature)

                .putHeader("content-type", "application/x-www-form-urlencoded")
                .setTimeout(Constants.REQUEST_TIMEOUT);
        return request;
    }

    public String getAPPBackgroundHost () {
        if (APPBACK_ISTEST) {
            return Constants.APPBACK_INTERFACE_HOST_TEST;
        } else {
            return Constants.APPBACK_INTERFACE_HOST;
        }
    }

    public Integer getAPPBackgroundPort() {
        if (APPBACK_ISTEST) {
            return Constants.APPBACK_INTERFACE_PORT_TEST;
        } else {
            return Constants.APPBACK_INTERFACE_PORT;
        }
    }

    /**
     * 发送一个GET请求
     * @param type
     * @param uri
     * @param bodyHandler
     */
    public void getGetRequest(String type, String uri, Handler<Buffer> bodyHandler) {
        switch (type) {
            case "wx" :
                client.getNow(
                        new RequestOptions()
                                .setHost(Constants.WX_INTERFACE_HOST)
                                .setPort(Constants.WX_INTERFACE_SSLPORT)
                                .setSsl(true)
                                .setURI(uri), resp -> {
                            resp.bodyHandler(bodyHandler);
                            resp.exceptionHandler(exceptionAr -> {
                                LOGGER.info("微信GET请求异常uri=[{}],error=[{}]", uri, exceptionAr.getMessage());
                                exceptionAr.printStackTrace();
                            });
                        });
                break;
            case "rc" :

                break;
            case "app" :
                client.getNow(
                        new RequestOptions()
                        .setHost(getAPPBackgroundHost())
                        .setPort(getAPPBackgroundPort())
                        .setURI(uri), resp -> {
                    resp.bodyHandler(bodyHandler);
                    resp.exceptionHandler(excep -> {
                        LOGGER.info("App GET请求异常uri=[{}],error=[{}]", uri, excep.getMessage());
                        excep.printStackTrace();
                    });
                });
                break;

            default :break;
        }
    }

    /**
     * 发送一个POST请求
     * @param type
     * @param uri
     * @param requestBody
     * @param bodyHandler
     */
    public void getPostRequest(String type, String uri,String requestBody, Handler<Buffer> bodyHandler) {
        switch (type) {
            case "wx" :
                HttpClientRequest request = client.post(new RequestOptions()
                                .setHost(Constants.WX_INTERFACE_HOST)
                                .setPort(Constants.WX_INTERFACE_SSLPORT)
                                .setSsl(true)
                                .setURI(uri)
                        , response -> {
                            response.bodyHandler(bodyHandler);
                            response.exceptionHandler(exceptionAr -> {
                                LOGGER.info("微信POST请求异常uri=[{}],error=[{}]", uri, exceptionAr.getMessage());
                                exceptionAr.printStackTrace();
                            });
                        });
                request
                        .putHeader("content-type", "text/plain")
                        .end(requestBody);
                break;
            case "rc" :
                HttpClientRequest rcRequest = client.post(new RequestOptions()
                                .setHost(Constants.RC_INTERFACE_HOST)
                                .setPort(Constants.RC_INTERFACE_PORT)
                                .setURI(uri)
                        , response -> {
                            response.bodyHandler(bodyHandler)
                                    .exceptionHandler(exception -> {
                                        LOGGER.info("融云POST请求异常uri=[{}],error=[{}]", uri, exception.getMessage());
                                        exception.printStackTrace();
                            });
                        });
                // 设置请求头并发送
                setRCRequestHeaders(rcRequest).end(requestBody);
                break;
            case "app" :
                client.post(new RequestOptions()
                        .setHost(getAPPBackgroundHost())
                        .setPort(getAPPBackgroundPort())
                        .setURI(uri), resp -> {
                    resp.bodyHandler(bodyHandler);
                    resp.exceptionHandler(excep -> {
                        LOGGER.info("App POST请求异常uri=[{}],error=[{}]", uri, excep.getMessage());
                        excep.printStackTrace();
                    });
                })
                        .putHeader("content-type", "text/json")
                        .end(requestBody);
                break;

            default :break;
        }
    }

}
